require "yaml"
module EncodeToSQL
  private
  def make_a_short_sequence_list_of_corpora(keywords)
    search_type = YAML.load_file("config/segment_search_type.yml")
    conditions = keywords.map{|keyword|
      modified = keyword.map{|key,value|
        if search_type["equal"].include?(key)
          "#{key} = '#{value}'"
        end
      }.compact
      unless modified.empty?
        "(" + modified.join(" AND ") + ")"
      else
        nil
      end
    }.compact
    unless conditions.empty?
      "SELECT corpora.* " +
      "FROM (" +
      "SELECT corpus_id " +
      "FROM corpora_segments " +
      "WHERE segment_id IN " +
      "(SELECT id FROM segments WHERE #{conditions.join(" OR ")}) " +
      "GROUP BY corpus_id " +
      "ORDER BY corpus_id ASC" +
      ") as assign " +
      "LEFT OUTER JOIN corpora " +
      "ON assign.corpus_id = corpora.id"
    else
      nil
    end
  end

  def make_a_short_list_of_corpora(keywords)
    search_type = YAML.load_file("config/segment_search_type.yml")
    conditions = keywords.map{|keyword|
      modified = keyword.map{|key,value|
        if search_type["equal"].include?(key)
          "#{key} = '#{value}'"
        end
      }.compact
      unless modified.empty?
        "(" + modified.join(" AND ") + ")"
      else
        nil
      end
    }.compact
    unless conditions.empty?
      "SELECT corpora.* " +
      "FROM (" +
      "SELECT corpus_id " +
      "FROM corpora_segments " +
      "WHERE segment_id IN " +
      "(SELECT id FROM segments WHERE #{conditions.join(" OR ")}) " +
      "GROUP BY corpus_id " +
      "ORDER BY corpus_id ASC" +
      ") as assign " +
      "LEFT OUTER JOIN corpora " +
      "ON assign.corpus_id = corpora.id"
    else
      nil
    end
  end
  
  def strings_select_sql(keywords,center_uniq=false)
    center = make_substr_sql("sequence",to_sequence_regexp(keywords))
    return "#{center} as center" if center_uniq
    left   = make_substr_sql(rtrim(make_split_part("sequence",center,1)),'[^[:space:]]+?$')
    right  = make_substr_sql(ltrim(make_split_part("sequence",center,2)),'^[^[:space:]]+' )
    return "#{left} as left_side,#{center} as center,#{right} as right_side"
  end
  
  def word_select_sql(keywords,center_uniq=false)
    center = trim(make_substr_sql("sequence",to_word_regexp(keywords)))
    return "#{center} as center" if center_uniq
    left   = make_substr_sql(rtrim(make_split_part("sequence",center,1)),'[^[:space:]]+?$')
    right  = make_substr_sql(ltrim(make_split_part("sequence",center,2)),'^[^[:space:]]+' )
    return "#{left} as left_side,#{center} as center,#{right} as right_side"
  end
  
  def word_sequence_select_sql(inputs)
    load_config if @enable_tags.nil?
    center = make_substr_sql("data",to_word_sequence_regexp(inputs,true))
    index = inputs["center_word"].to_i
    no_marking_regexp = to_word_sequence_regexp(inputs)
    no_marking_sequence = make_substr_sql("data",no_marking_regexp)
    left  = left_side_sql(inputs,center,no_marking_regexp,no_marking_sequence,index)
    right = right_side_sql(inputs,center,no_marking_regexp,no_marking_sequence,index)
    return "#{left} as left_side,#{center} as center,#{right} as right_side"
  end
  
  def uniq_word_sequence_select_sql(inputs,center_uniq=false)
    load_config if @enable_tags.nil?
    center = make_substr_sql("data",to_word_sequence_regexp(inputs,true))
    index = inputs["center_word"].to_i
    return "#{center} as center" if center_uniq
    keyword_locations = inputs["locations"].map{|location| encode_locate(location) }
    searchable_keywords = inputs["keywords"].map{|keyword| searchable_tags(keyword) }
    return Array.new(inputs["keywords"].size){|index|
      keywords = searchable_keywords.dup
      keywords[index] = "(#{searchable_keywords[index]})"
      word_regexp = keywords.zip(keyword_locations).join
      "#{make_substr_sql("data",word_regexp)} as word#{index}"
    }.join(",")
  end
  
  def left_side_sql(inputs,center,no_marking_regexp,no_marking_sequence,index)
    if index == 0
      return make_substr_sql("data","([^[:space:]]+[[:space:]])#{no_marking_regexp}") 
    else
      return make_substr_sql(make_split_part(no_marking_sequence,center,1),"([^[:space:]]+[[:space:]])$")
    end
  end

  def right_side_sql(inputs,center,no_marking_regexp,no_marking_sequence,index)
    if (inputs["keywords"].size - 1) == index
      return make_substr_sql("data","#{no_marking_regexp}([^[:space:]]+[[:space:]])")
    else
      return make_substr_sql(make_split_part(no_marking_sequence,center,2),"^([^[:space:]]+[[:space:]])")
    end
  end
    
  def to_word_regexp(keywords)
    keywords.map{|keyword| enable_around_space(keyword) }.join('|')
  end

  def to_sequence_regexp(keywords)
    keywords.map{|keyword| match_word_unit(keyword) }.join('|')
  end
  
  def to_word_sequence_regexp(inputs,center_marking=false)
    load_config if @enable_tags.nil?
    searchable_keywords = inputs["keywords"].map{|keyword| searchable_tags(keyword) }
    keyword_locations = inputs["locations"].map{|location| encode_locate(location) }
    if center_marking
      index = inputs["center_word"].to_i
      searchable_keywords[index] = "(#{searchable_keywords[index]})"
    end
    searchable_keywords.zip(keyword_locations).join
  end
  
  def load_config
    tags = YAML.load_file("config/corpus_info.yml")["tags"]
    @tag_list = YAML.load_file("config/split_tags.yml")
    @enable_tags = tags & @tag_list.keys
  end
  
  def searchable_tags(keyword)    
    @search_type = YAML.load_file("config/segment_search_type.yml") if @search_type.nil?
    conditions = @enable_tags - keyword.keys
    tag_regexp = conditions.empty? ? '' : '(?:(?:' + conditions.map{|tag| Regexp.escape(@tag_list[tag]) }.join('|') + ')[^[:space:]]+?)*?'
    word = (@enable_tags & keyword.keys).map{|tag|
      escaped = Regexp.escape(@tag_list[tag]+keyword[tag])
      if @search_type["equal"].include?(tag)
        escaped += tag_regexp 
      else
        escaped += "[^[:space:]]*?"
      end
      escaped
    }.join("") 
    "[^[:space:]]*?#{word}[[:space:]]"
  end
  
  def encode_locate(location)
    if location == '<'
      ".*?" # これでホントに大丈夫かはちょっと微妙
    else
     "(?:[^[:space:]]+[[:space:]]){#{location}}" # これも色々な例で検証
    end
  end

  def enable_space(keyword)
    keyword.split(//).join('[[:space:]]?')
  end
    
  def enable_around_space(keyword)
    "[[:space:]]?#{keyword}[[:space:]]?"
  end
  
  def match_word_unit(keyword)
    "[^[:space:]]*#{enable_space(keyword)}[^[:space:]]*"
  end
  
  def make_sequence_group(size)
    Array.new(size){|i| "word#{i}" }.join(",")
  end
  
  def make_substr_sql(column_name,regexp)
    "substring(#{column_name} from '#{regexp}')"
  end
  
  def make_split_part(column_name,delimiter,field)
    "split_part(#{column_name},#{delimiter},#{field})"
  end
  
  def trim(strings)
    "trim(both from #{strings})"
  end
  
  def rtrim(strings)
    "rtrim(#{strings})"
  end
  
  def ltrim(strings)
    "ltrim(#{strings})"
  end
  
end